package com.letv.so.service.thrift.detail;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import net.rubyeye.xmemcached.MemcachedClient;

import org.apache.commons.lang.StringUtils;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TMemoryBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import serving.AlbumAttribute;
import serving.ContentProviderAttribute;
import serving.DataType;
import serving.ResultDocInfo;
import serving.VideoAttributeInAlbum;
import serving.VideoIndex;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.letv.so.bean.AlbumBean;
import com.letv.so.service.QueryDataService;
import com.letv.so.service.impl.ByteTranscoder;
import com.letv.so.util.BisUtil;
import com.letv.so.util.StringUtil;

/**
 * thrift detail interface : static mathod for cp
 */
public class CpDetail {

    /**
     * String, cp category and unid split
     */
    private static String CP_SPLIT = "-";

    /**
     * Logger
     */
    private static Logger LOGGER = LoggerFactory.getLogger(CpDetail.class);

    /**
     * get cp detail
     * this method will not check parameters which passed in and hold that letvOrginalId is cp
     * @param queryDataService QueryDataService, get data from memached.It's used to get two tytes of data:
     *                                           1.json data stored by offlinetask
     *                                           2.thrift data stored by offlinetask
     * @param memcachedClient MemcachedClient, get data from memached.It's used to get thrift data stored by pipline
     * @param letvOrginalId String, letv perfix with cp id. for more information please visit the page following:
     *                              http://wiki.letv.cn/pages/viewpage.action?pageId=52863107 
     * @param timeStamp Long, get by Long, System.currentTimeMillis() when request comes.It's used to mark the request
     * @param fromIndex int, begin id of album index at album list in cp
     * @param pageSize int, element numbuer of album index at album list in cp
     * @param cpRequestType int, 0--album 1--video
     * @return ResultDocInfo, return null if there is no data or have erors
     */
    static ResultDocInfo getCp(QueryDataService queryDataService, MemcachedClient memcachedClient, String letvOrginalId, Long timeStamp, int fromIndex, int pageSize, int cpRequestType) {
        byte[] cbaseValue = null;
        try {
            cbaseValue = queryDataService.getThrift(letvOrginalId);
        } catch(Exception e) {
            LOGGER.error("error to get cpinfo from cbase of offline,timeStamp=" + timeStamp.toString() + ",key=" + letvOrginalId, e);
            return null;
        }

        ResultDocInfo resultDocInfo = null;
        if (null == cbaseValue) {
            try {
                cbaseValue = memcachedClient.get(letvOrginalId, new ByteTranscoder());
                if(null != cbaseValue) {
                    resultDocInfo = StringUtil.byte2ResultDocInfo(cbaseValue);
                }
            } catch (Exception e) {
                LOGGER.error("error to get cpinfo from cbase of pipeline,sid=" + timeStamp.toString() + ",key=" + letvOrginalId, e);
                return null;
            }
        }

        if(null == cbaseValue) {
            LOGGER.warn("key:" + letvOrginalId + " get value from cbase is null!");
            return null;
        }

        ContentProviderAttribute cpInfo = null;
        if(null == resultDocInfo) {
            try {
                TMemoryBuffer tMemoryBuffer = new TMemoryBuffer(32);
                TBinaryProtocol tBinaryProtocol = new TBinaryProtocol(tMemoryBuffer);
                tMemoryBuffer.write(cbaseValue, 0, cbaseValue.length - 1);
                cpInfo = new ContentProviderAttribute();
                cpInfo.read(tBinaryProtocol);
            } catch(Exception e) {
                LOGGER.error("error to transform cpinfo to thrift object from thrift byte[],sid=" + timeStamp.toString() + ",key=" + letvOrginalId, e);
                return null;
            }
        } else {
            cpInfo = resultDocInfo.getContent_provider_attribute();
        }
        if(null == cpInfo) {
            return null;
        }

        if(cpRequestType == 0) {
            CpDetail.setAlbumList(queryDataService, cpInfo, timeStamp, fromIndex, pageSize);
        } else if(cpRequestType == 1) {
            CpDetail.setVideoList(queryDataService, cpInfo, timeStamp, fromIndex, pageSize);
        }

        ResultDocInfo result = null;
        try {
            result = new ResultDocInfo("", DataType.CP);
            result.setContent_provider_attribute(cpInfo);
            cpInfo.setVideo_index_list(null);
        } catch(Exception e) {
            LOGGER.error("error to set CPInfo into ResultDocInfo,sid=" + timeStamp.toString() + ",key=" + letvOrginalId, e);
            return null;
        }
        return result;
    }

    /**
     * set video list to cp
     * this method will not check parameters which passed in
     * @param queryDataService QueryDataService, get data from memached.It's used to get two tytes of data:
     *                                           1.json data stored by offlinetask
     *                                           2.thrift data stored by offlinetask
     * @param cpInfo ContentProviderAttribute, cp thrift struct data
     * @param timeStamp Long, get by Long, System.currentTimeMillis() when request comes.It's used to mark the request
     * @param fromIndex int, begin id of video index at video list in cp
     * @param pageSize int, element numbuer of video index at video list in cp
     */
    private static void setVideoList(QueryDataService queryDataService, ContentProviderAttribute cpInfo, Long timeStamp, int fromIndex, int pageSize) {
        List<VideoIndex> videoIndexList = cpInfo.getVideo_index_list();
        if(null == videoIndexList || videoIndexList.size() == 0) {
            return;
        }
        int videoIndexListSize = cpInfo.getVideo_index_list().size();
        int toIndex = fromIndex + pageSize;
        if (fromIndex >= videoIndexListSize) {
            return;
        }
        if (toIndex > videoIndexListSize) {
            toIndex = videoIndexListSize;
        }
        List<VideoIndex> subVideoIndexList = videoIndexList.subList(fromIndex, toIndex);
        if(null == subVideoIndexList || subVideoIndexList.size() == 0) {
            return;
        }

        List<VideoAttributeInAlbum> videoList = new ArrayList<VideoAttributeInAlbum>();
        for(int i = 0; i < subVideoIndexList.size(); i++) {
            try {
                AlbumAttribute albumAttribute = CpDetail.getAlbumById(queryDataService, subVideoIndexList.get(i).getAlbum_id() + "", timeStamp, false, null, null, subVideoIndexList.get(i).getVideo_index(), 1);
                videoList.add(albumAttribute.getVideo_list().get(0));
            } catch(Exception e) {
                continue;
            }
        }
        cpInfo.setVideo_list(videoList);
    }

    /**
     * set album list to cp
     * this method will not check parameters which passed in
     * @param queryDataService QueryDataService, get data from memached.It's used to get two tytes of data:
     *                                           1.json data stored by offlinetask
     *                                           2.thrift data stored by offlinetask
     * @param cpInfo ContentProviderAttribute, cp thrift struct data
     * @param timeStamp Long, get by Long, System.currentTimeMillis() when request comes.It's used to mark the request
     * @param fromIndex int, begin id of album index at album list in cp
     * @param pageSize int, element numbuer of album index at album list in cp
     */
    private static void setAlbumList(QueryDataService queryDataService, ContentProviderAttribute cpInfo, Long timeStamp, int fromIndex, int pageSize) {
        String albumIdListStr = cpInfo.getAlbum_id_list();
        List<AlbumAttribute> albumAttributeList = null;
        List<String> albumCategoryList = null;
        List<String> unIdList = null;
        if(!StringUtils.isBlank(albumIdListStr)) {
            List<String> albumIdList = CpDetail.getAlbumIdListInCp(albumIdListStr, fromIndex, pageSize);
            if(null != albumIdList) {
                albumAttributeList = new ArrayList<AlbumAttribute>();
                albumCategoryList = new ArrayList<String>();
                unIdList = new ArrayList<String>();
                for(String albumId : albumIdList) {
                    if(StringUtils.isBlank(albumId)) {
                        continue;
                    }
                    try {
                        AlbumAttribute albumAttribute = CpDetail.getAlbumById(queryDataService, albumId, timeStamp, true, albumCategoryList, unIdList, 0, 0);
                        if(null != albumAttribute) {
                            albumAttributeList.add(albumAttribute);
                        }
                    } catch(Exception e) {
                        continue;
                    }
                }
            }
        }
        cpInfo.setAlbum_attribute_list(albumAttributeList);
        cpInfo.setAlbum_category_list(albumCategoryList);
        cpInfo.setAlbum_unid_list(unIdList);
    }

    /**
     * get album id list in cp_info by page
     * this method will not check parameters which passed in
     * @param albumIdListStr String, album id split by comma
     * @param fromIndex int, begin id of album index at album list in cp
     * @param pageSize int, element numbuer of album index at album list in cp
     * @return List<String>, return null if there is no data or have errors
     */
    private static List<String> getAlbumIdListInCp(String albumIdListStr, int fromIndex, int pageSize) {
        String[] albumIdArray = albumIdListStr.split(",");
        if(null == albumIdArray || albumIdArray.length == 0) {
            return null;
        }

        int toIndex = fromIndex + pageSize;
        if (fromIndex >= albumIdArray.length) {
            return null;
        }
        if (toIndex > albumIdArray.length) {
            toIndex = albumIdArray.length;
        }

        List<String> result = null;
        try {
            List<String> albumIdList = Arrays.asList(albumIdArray);
            result = BisUtil.subList(fromIndex, toIndex, albumIdList);
            if(null != result && result.size() == 0) {
                result = null;
            }
        } catch(Exception e) {
            result = null;
        }
        return result;
    }

    /**
     * get AlbumAttribute by album_id
     * this method will not check parameters which passed in
     * @param queryDataService QueryDataService, get data from memached.It's used to get two tytes of data:
     *                                           1.json data stored by offlinetask
     *                                           2.thrift data stored by offlinetask
     * @param lesoAid String, leso album id
     * @param ifGetNew boolean, true --get last video of album
     *                          false--get video in region of album
     * @param timeStamp Long, get by Long, System.currentTimeMillis() when request comes.It's used to mark the request
     * @param albumCategoryList List<String>, album category list.each album will add itself's category to this list if need(null != albumCategoryList)
     * @param unIdList String, top single_video unid list.each album will add itself's top unid to this list if need(null != unIdList)
     * @param fromIndex int, begin index of video list,include.give 0 if don't need this parameter
     * @param pageSize int, videoCount.give 0 if don't need this parameter
     * @return AlbumAttribute, return null if there is no data or have errors
     */
    private  static AlbumAttribute getAlbumById(QueryDataService queryDataService, String lesoAid, Long timeStamp, boolean ifGetNew, List<String> albumCategoryList, List<String> unIdList, int fromIndex, int pageSize) {
        String soKey = "newmms_leso_a_" + lesoAid;
        String soData = queryDataService.get(timeStamp.toString(), "inc" + soKey);
        if (StringUtils.isBlank(soData)) {
            soData = queryDataService.get(timeStamp.toString(), soKey);
        }
        if (StringUtil.isBlank(soData)) {
            LOGGER.warn("soKey:" + soKey + " get value from cbase is null!");
            return null;
        }
        AlbumBean album = null;
        try {
            album = JSON.parseObject(soData, AlbumBean.class);
        } catch (Exception e) {
            LOGGER.error("error to tansfam to object form json, key=" + soKey, e);
            return null;
        }
        if (null == album) {
            LOGGER.warn(timeStamp + " ,soKey:"+soKey +" album==null");
            return null;
        }
        try {
            JSONObject source_list_json = album.getSource_list_json();
            String source_list = null==source_list_json.getString("default") ? "" : source_list_json.getString("default");
            album.setSource_list(source_list);
            album.setSource_list_json(null);
        } catch(Exception e) {
        }
        if(ifGetNew) {
            CpDetail.setNewVideo(timeStamp, soKey, album, albumCategoryList, unIdList);
        } else {
            CpDetail.setVideoList(timeStamp, soKey, album, fromIndex, pageSize);
        }

        ResultDocInfo resultDocInfo = BisUtil.album2thrift(album);
        if(null == resultDocInfo) {
            return null;
        }
        return resultDocInfo.getAlbum_attribute();
    }

    /**
     * get AlbumAttribute by album_id
     * this method will not check parameters which passed in
     * @param timeStamp Long, get by Long, System.currentTimeMillis() when request comes.It's used to mark the request
     * @param soKey String, key for query in cbase
     * @param album AlbumBean, album detail
     * @param fromIndex int, begin index of video list,include
     * @param pageSize int, video count
     */
    private static void setVideoList(Long timeStamp, String soKey, AlbumBean album, int fromIndex, int pageSize) {
        CommonDetail.setVideoList(timeStamp.toString(), soKey, album, fromIndex, pageSize);
    }

    /**
     * set new video to album
     * this method will not check parameters which passed in
     * @param timeStamp Long, get by Long, System.currentTimeMillis() when request comes.It's used to mark the request
     * @param soKey String, key for query in cbase
     * @param album AlbumBean, album detail
     * @param albumCategoryList List<String>, album category list.each album will add itself's category to this list
     * @param unIdList String, top single_video unid list.each album will add itself's top unid to this list
     */
    private static void setNewVideo(Long timeStamp, String soKey, AlbumBean album, List<String> albumCategoryList, List<String> unIdList) {
        String category = album.getCategory();
        if(null != category) {
            albumCategoryList.add(album.getAid() + CpDetail.CP_SPLIT + category);
            try {
                ArrayList<String> globalVids = new ArrayList<String>();
                BisUtil.convertStr2List(album.getUnIds(), globalVids);
                boolean desc = category.equals("11") || category.equals("16") || category.equals("101") || category.equals("4");
                if(desc) {
                    CommonDetail.setVideoList(timeStamp.toString(), soKey, album, 0, 1);
                    if(null != globalVids && globalVids.size() > 0) {
                        unIdList.add(album.getAid() + CpDetail.CP_SPLIT + globalVids.get(0));
                    }
                } else {
                    String videoPlayUrls = album.getVideoPlayUrls();
                    if (!StringUtil.isBlank(videoPlayUrls)) {
                        String[] videoArray = videoPlayUrls.split(";");
                        if(videoArray.length > 0) {
                            CommonDetail.setVideoList(timeStamp.toString(), soKey, album, videoArray.length - 1, 1);
                        }
                    }
                    if(null != globalVids && globalVids.size() > 0) {
                        unIdList.add(album.getAid() + CP_SPLIT + globalVids.get(globalVids.size() - 1));
                    }
                }
            } catch(Exception e) {
                LOGGER.error("error to get top single video for cp,key=" + soKey, e);
            }
        }
    }
}
